"use strict"
/*
    微信开放平台
    文档地址：https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN
 */


const login_url = {
    "sandbox":"https://api.weixin.qq.com/sns/oauth2",
    "production":"https://api.weixin.qq.com/sns/oauth2",
}


const payment_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';

const userinfo_url = 'https://api.weixin.qq.com/sns';

exports.format = {
    "id":'weixin',
    "name":"微信开放平台[扫码登录]",
    "fields":{
        "appid" :{'type':'string','val':'','name':"appid"},
        "mchid" :{'type':'string','val':'',"name":"mchid:商户号[仅充值使用]"},
        "secret" :{'type':'string','val':'','name':"secret"},
    }
}
//登录与认证TOKEN
exports.login = function () {
    let code = this.get("code",'string')
    if(!code){
        return this.error("code empty");
    }
    if(!this.opensdk.setting || !this.opensdk.setting.appid || !this.opensdk.setting.secret){
        return this.error("opensdk.setting empty");
    }
    let api = "/access_token";
    let host = (this.opensdk.status > 0 ? login_url.production : login_url.sandbox) + api;
    let args = {"appid":this.opensdk.setting.appid,"secret":this.opensdk.setting.secret,"code":code,"grant_type":"authorization_code"};

    // let data = null;
    // let url = host + '?' + querystring.stringify(args);
    // console.log("url",url)

    return this.library("request/get", host, args).then(ret=>{
        if( ret["errcode"] ){
            return this.error(`${ret["errmsg"]}[${ret["errmsg"]}]` )
        }
        //let expires = Date.now() + body["expires_in"] * 1000;
        let token = {};
        //token['unionid'] = ret["unionid"];
        token['access']  = ret["access_token"];
        token['expire'] = Date.now() + ret["expires_in"] * 1000;
        token['refresh'] = ret["refresh_token"];

        return {"openid":ret["openid"],"token":token }
    })
}



//获取用户详细名称，头像等。。。
exports.userinfo = function () {
    let access = this.get("access",'string');
    if(!access){
        return this.error("access empty");
    }
    return get_weixin_token.call(this,access).then(ret=>{
        let api = "/userinfo";
        let host = userinfo_url + api;
        let args = {"openid":ret['openid'],"access_token":ret['token']['access']};
        return this.library("request/get", host, args)
    }).then(ret=>{
        if( ret["errcode"] ){
            return this.error(`${ret["errmsg"]}[${ret["errmsg"]}]` )
        }
        else{
            return ret;
        }
    })
}


/**
 * @name createOrder
 * 创建订单
 */
exports.orderCreate = function(config){
    if(!this.opensdk.setting || !this.opensdk.setting.appid || !this.opensdk.setting.mchid || !this.opensdk.setting.secret){
        return this.error("opensdk.setting error");
    }
    let id = config["orderid"],data = {},setting = this.opensdk.setting;

    data["appid"] = setting["appid"];
    data["mch_id"] = setting["mchid"];
    //data["device_info"] = "WEB";
    data["nonce_str"] = String(Date.now());
    //data["sign_type"] = "MD5";

    data["body"] = this.get("title","string");
    data["detail"] = this.get("body","string");
    data["attach"] = config["attach"];
    data["out_trade_no"] = id;
    //data["fee_type"] = "CNY";
    data["total_fee"] = parseInt(config["rmb"] * 100);
    data["spbill_create_ip"] = this.req.ip.replace("::ffff:",'');
    //data["time_start"] = $.time.format("yyyyMMddhhmmss");
    //data["time_expire"] = $.time.format("yyyyMMddhhmmss");
    data["notify_url"] = `${this.req.protocol}://${this.req.hostname}/${this.branch}/${this.opensdk._id}/order/notify`;
    data["trade_type"] = "APP";
    ///////////////////////////////////开始签名//////////////////////////////////////
    data["sign"] = verifySign(data,setting["secret"]);
    //转换成XML
    let xml2js = require('xml2js');
    let xmlBuilder = new xml2js.Builder({"rootName":"xml","headless":true});
    let xmlData = xmlBuilder.buildObject(data);
    return this.library("request/post",payment_url,xmlData).then(ret=>{
        return  {"id":id,"attach":data["attach"],"timestamp":Date.now(), "body" : ret };
    })
}


/**
 * @name notify
 * 支付回调
 */

exports.orderNotify = function(){
    //this.debug = 1;
    let body = this.req.body;
    if(typeof body !=="string" || body.substr(0,5)!=="<xml>"){
        return Promise.reject("body not xml");
    }
    let xml2js = require('xml2js');
    let xmlParser = new xml2js.Parser({explicitArray: false, ignoreAttrs: true});
    return this.library.call(xmlParser,"promise",'parseString',body).then(xml=>{
        if(!xml.xml){
            return Promise.reject("body xml error");
        }
        return xml.xml;
    }).then(ret=>{
        if(ret["result_code"] !== "SUCCESS"){
            return Promise.reject("err_code");
        }
        let sign = ret["sign"]
        delete ret["sign"];
        let servSign = verifySign.call(this,ret,this.opensdk.setting.secret);
        if(sign !== servSign){
            return Promise.reject("sign error");
        }
        return {"attach":ret["attach"],"orderid":ret["out_trade_no"]}
    })
}



exports.orderResult = function (err,ret){
    this.output = 'xml';
    let xml2js = require('xml2js');
    let xmlBuilder = new xml2js.Builder({"rootName":"xml","headless":true});
    let data;
    if(err){
        data = {"return_code":"FAIL","return_msg":err}
    }
    else{
        data = {"return_code":"SUCCESS","return_msg":ret}
    }
    return  xmlBuilder.buildObject(data);
}


function verifySign(data,key){
    let arr=[];
    let keys = Object.keys(data).sort();
    for(let k of keys){
        let v = data[k];
        arr.push(k+"="+v);
    }
    arr.push("key="+key);
    let str = arr.join("&");
    let sign = this.library("crypto/md5",str);
    return sign.toUpperCase();
}


//刷新TOKEN，返回新的token,不需要刷新时返回false;
//返回新的TOKEN时，调用端需要自己保存
function get_weixin_token(access){
    let query = {"access":access};
    let option = {multi:false,fields:{'openid':1,"token":1} };
    let openidModel = this.model.branch("openid",this.branch);
    let openidData;
    return openidModel.find(query,option).then(ret=>{
        if(!ret){
            return this.error("access not exist");
        }
        if(!ret['token'] || !ret['openid'] ){
            return this.error("openid or token empty");
        }
        openidData = ret;
        if( openidData['token']['expire'] < Date.now() ){
            return false;
        }
        let api = "/refresh_token";
        let host = (this.opensdk.status > 0 ? login_url.production : login_url.sandbox) + api;
        let args = {"appid":this.opensdk.setting.appid,"refresh_token":openidData['token']['refresh'],"grant_type":"refresh_token"};
        return this.library("request/get", host, args);
    }).then((ret)=>{
        if(!ret){
            return ;
        }
        if( ret["errcode"] ){
            return this.error(`${ret["errmsg"]}[${ret["errmsg"]}]` )
        }
        openidData['token']['access']  = ret["access_token"];
        openidData['token']['expire'] = Date.now() + ret["expires_in"] * 1000;
        openidData['token']['refresh'] = ret["refresh_token"];
        return openidModel.set(openidData['_id'],'token',openidData['token']);
    }).then(()=>openidData);
}
